package com.dragon.geekbang.thinking.in.spring.ioc.container.overview.dependency.injection;


import com.dragon.geekbang.thinking.in.spring.ioc.container.overview.domain.repository.UserRepository;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.env.Environment;


/**
 * 依赖注入示例
 * IOC 依赖来源
 * 1.自定义 Bean
 * 2.内置 Bean
 * 3.容器内置依赖（资源）
 */
public class DependencyInjectionDemo {

    public static void main(String[] args) {

        // 配置 XML 配置文件
        // 启动 Spring 应用上下文
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/META_INF/dependency-injection-context.xml");

        // 依赖查找
        UserRepository userRepository = applicationContext.getBean(UserRepository.class);
        // 依赖注入 用户自定义的Bean
        System.out.println(userRepository.getUsers());
        // 依赖注入 内置的非Bean
        System.out.println(userRepository.getBeanFactory());
        System.out.println(userRepository.getBeanFactory() == applicationContext);

        System.out.println(userRepository.getResourceLoader());
        System.out.println(userRepository.getApplicationEventPublisher());

        // 依赖查找 内置的非Bean（错误，无法获取到）
//        System.out.println(beanFactory.getBean(BeanFactory.class));

        // 延迟注入
        System.out.println(userRepository.getUserObjectFactory().getObject());

        System.out.println(userRepository.getApplicationContextObjectFactory().getObject());
        System.out.println(applicationContext == userRepository.getApplicationContextObjectFactory().getObject());

        // 依赖查找 内置的 Bean
        System.out.println(applicationContext.getBean(Environment.class));

        whoIsIocContainer(userRepository.getBeanFactory(), applicationContext);
    }

    private static void whoIsIocContainer(BeanFactory factory, BeanFactory factory2){
        /**
         * 类似装饰模式
         * 实际底层的 Ioc 容器是 Beanfactory：DefaultListableBeanFactory
         * ApplicationContext 是 BeanFactory的超类 且包含一个 Beanfactory的实际实现（DefaultListableBeanFactory）
         * 自动注入的时候，注入的是DefaultListableBeanFactory而不是ApplicationContext
         *
         * 除了Ioc
         * ApplicationContext还提供：
         * AOP
         * 配置元信息
         * 资源管理
         * 事件
         * 国际化
         * 注解
         * Environmenet抽象
         */
        // 表达式为什么不成立
        System.out.println(factory == factory2);
        System.out.println("factory:" + factory);
        System.out.println("factory2:" + factory2);

    }


}
